home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Dos / VARIOS / pascal / SWAG9605.DDD / 0132_INI files - Revised.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-05-31  |  6.8 KB  |  326 lines

  1. {I found a few errors and made a few improvements with my INI file
  2. handler I posted this earlier.}
  3.  
  4. {$A+,B-,D-,F-,G-,I-,L-,N-,O-,P-,Q-,R-,S+,T-,V-,X+}
  5.  
  6. {INI  Version 1.2   Copr. 1996 Brad Zavitsky
  7.  FREEWARE: Swag/Commercial use fine
  8.  
  9. Thanks to Andrew Eigus for his great EnhDos unit from which I got
  10. Pas2Pchar
  11.  
  12. Version Info
  13. 1.1
  14. ====
  15.   o Fixed error, needed StrNew instead of StrCopy
  16.   o Added support for TP6- users.
  17.  
  18. 1.2
  19. ====
  20.   o  Better memory detection: now find paragraph size
  21.   o  Optimized memory testing
  22.   o  Entries will not be added if the entry or value is blank
  23.   o  Fixed bug in split
  24.   o  Added a comment delimeter set
  25.   o  Added comments to source code
  26.   o  Optimized space/tab stripping for memory
  27.   o  Made FName a constant
  28.   o  Made list global
  29. }
  30.  
  31. unit INI; {031496}
  32.  
  33. interface
  34.  
  35. {$IFDEF VER70}
  36. uses Strings;
  37. {$ENDIF}
  38.  
  39. type
  40.   CSet = set of Char;
  41.   TEntry = string[32];
  42.   {Linked list to store INI entries and values}
  43.   PEntryList = ^TEntryList;
  44.   TEntryList = record
  45.      Entry,
  46.      Value: PChar;
  47.      Next: PEntrylist;
  48.   end;
  49.  
  50. const
  51.   {If these characters precede a line, it will be counted as a comment}
  52.   CommentDelim: CSet = [';','[','#'];
  53.  
  54. var
  55.   List: PEntryList; {Holds entries and values}
  56.  
  57.  
  58. {Load the ini file into a linked list; this must be done before 
  59. attempting
  60. to get any entries
  61. Returns:
  62.   0 = Everything is fine
  63.   1 = Error opening (ie.. File not found)
  64.   2 = Not enough memory (remember to call freeini to get rid of already
  65.       stored variables}
  66. function LoadINI(const FName: string): Integer;
  67. {Frees the memory allocated from LoadINI}
  68. procedure FreeINI;
  69. {Gets the value from a specified entry}
  70. function GetEntry(Entry: TEntry; const Default: string): string;
  71.  
  72. implementation
  73.  
  74. var
  75.   S,E,V: string; {Temporary strings, E=Entry, V=Value}
  76.   Temp: PChar;   {Used to store a string as a PChar for StrComp}
  77.   T: Text;       {INI text file}
  78.   LNew: PEntryList; {New link}
  79.  
  80. {Pascal string to ASCIIZ; Thanks to Andrew Eigus}
  81. function Pas2PChar(const S : string) : PChar; assembler;
  82. asm
  83.   les di,S
  84.   mov al,byte ptr [es:di]
  85.   cmp al,0
  86.   je  @@1
  87.   push di
  88.   sub ah,ah
  89.   cld
  90.   inc al
  91.   stosb
  92.   add di,ax
  93.   dec di
  94.   sub al,al
  95.   stosb
  96.   pop di
  97. @@1:
  98.   inc di
  99.   mov dx,es
  100.   mov ax,di
  101. end; { Pas2PChar }
  102.  
  103. {ASCIIZ to Pascal}
  104. function PChar2Pas(P: PChar): string;
  105. var
  106.   IDX: Integer;
  107. begin
  108.   Idx := 0;
  109.   while P[IDX] <> #0 do
  110.   begin
  111.     PChar2Pas[succ(Idx)] := P[IDX];
  112.     inc(Idx);
  113.   end;
  114.   PChar2Pas[0] := Chr(Idx);
  115. end;
  116.  
  117. {Fast uppercase function}
  118. function UpperCase(const S: string): string; assembler;
  119. asm
  120.   push ds
  121.   lds si, s
  122.   les di, @result
  123.   lodsb
  124.   stosb
  125.   xor ch, ch
  126.   mov cl, al
  127.   jcxz @empty
  128. @upperloop:
  129.   lodsb
  130.   cmp al, 'a'
  131.   jb @cont
  132.   cmp al, 'z'
  133.   ja @cont
  134.   sub al, ' '
  135. @cont:
  136.   stosb
  137.   loop @upperloop
  138. @empty:
  139.   pop ds
  140. end;
  141.  
  142. {Removes all instances of DELCHAR from the right side of S}
  143. function CutRight(const S: string; DelChar: Char): string;
  144. var
  145.   Len: Byte;
  146. begin
  147.   CutRight := S;
  148.   Len := Ord(S[0]);
  149.   while S[Len] = DelChar do Dec(Len);
  150.   CutRight[0] := Chr(Len);
  151. end;
  152.  
  153. {Removes all instances of DELCHAR from the left side of S}
  154. function CutLeft(const S: string; DelChar: Char): string;
  155. var
  156.   Cnt: Byte;
  157. begin
  158.   Cnt := 1;
  159.   while S[Cnt] = DelChar do Inc(Cnt);
  160.   CutLeft := Copy(S, Cnt, Length(S)-pred(Cnt));
  161. end;
  162.  
  163. {Splits a INI string into 2 parts: the entry and value}
  164. procedure Split(const S: string; var E,V: string);
  165. var
  166.   len: Byte;
  167. begin
  168.   Len := Pos('=',S);
  169.   if Len <> 0 then
  170.   begin
  171.     V := Copy(S, succ(Len), succ(Length(S)-Len));
  172.     E := S;
  173.     E[0] := chr(pred(Len));
  174.     V := CutLeft(V, #32);
  175.     V := CutLeft(V, #9);
  176.     V := CutRight(V, #32);
  177.     V := CutRight(V, #9);
  178.     E := CutRight(E, #32);
  179.     E := CutRight(E, #9);
  180.   end else
  181.   begin      {Invalid entry}
  182.     E := '';
  183.     V := '';
  184.   end;
  185. end;
  186.  
  187. {String unit emulation}
  188. {$IFNDEF VER70}
  189. function StrNew(S: PChar): PChar;
  190. var
  191.   I,
  192.   L: Word;
  193.   P: PChar;
  194. begin
  195.   StrNew := nil;
  196.   if (S<>nil) and (S^ <> #0) then
  197.   begin
  198.     L := 0;
  199.     while S[L] <> #0 do inc(L);
  200.     inc(L);
  201.     GetMem(P,L);
  202.     if P <> nil then for I := 0 to L do P[I] := S[I];
  203.     StrNew := P;
  204.   end;
  205. end;
  206.  
  207. procedure StrDispose(S: PChar);
  208. var
  209.   L: Word;
  210. begin
  211.   L := 0;
  212.   while S[L] <> #0 do inc(L);
  213.   if S <> nil then FreeMem(S,succ(L));
  214. end;
  215.  
  216. function StrComp(Str1, Str2: PChar): Integer;
  217. var
  218.   L1,
  219.   L2: Word;
  220. begin
  221.   StrComp := 1;
  222.   L1 := 0;
  223.   while Str1[L1] <> #0 do inc(L1);
  224.   l2 := 0;
  225.   while Str2[L2] <> #0 do inc(L2);
  226.   if L1 <> L2 then exit;
  227.   for L1 := 0 to L2 do if Str1[L1] <> Str2[L1] then exit;
  228.   StrComp := 0;
  229. end;
  230.  
  231. {$ENDIF}
  232.  
  233. {Calculates the amount of memory that would be actually allocated;
  234.  Counts it in 16byte paragraphs}
  235. function MemUsed(M: Word): Word;
  236. var
  237.   R: Byte;
  238. begin
  239.   MemUsed := succ(M shr 4) shl 4;
  240. end;
  241.  
  242. function LoadINI(const FName: string): Integer;
  243. begin
  244.   assign(T, FName);
  245.   reset(T);
  246.   if IOResult <> 0 then {Exit if there is a file error}
  247.   begin
  248.     LoadINI := 1;
  249.     Exit;
  250.   end;
  251.  
  252.   while not Eof(T) do
  253.   begin
  254.     Readln(T, S);
  255.     S := uppercase(S);
  256.     S := CutLeft(S, #32); {Remove spaces and tabs}
  257.     S := CutLeft(S, #9);
  258.     {Make sure string is not a comment}
  259.     if not (S[1] in CommentDelim) and (Length(S) > 0) then
  260.     begin
  261.       Split(S, E, V); {Split string into entry and value}
  262.  
  263.       {When low on memory, start checking to make sure we have enough}
  264.       if MaxAvail < 300 then if MaxAvail < MemUsed(SizeOf(TEntryList)) +
  265.         MemUsed(succ(Length(V)))+ MemUsed(Succ(Length(E))) then
  266.       begin
  267.         LoadINI := 2;
  268.         {FreeINI;}
  269.         CLose(T);
  270.         Exit;
  271.       end;
  272.  
  273.       if (V <> '') and (E <> '') then
  274.       begin
  275.         {Add new link to list}
  276.         New(LNew);
  277.         {Allocate new copies on the stack; we don't want the PChar's
  278.          pointing to E and V}
  279.         Lnew^.Entry := StrNew(Pas2Pchar(E));
  280.         Lnew^.Value := StrNew(Pas2Pchar(V));
  281.         Lnew^.Next := List;
  282.         List := LNew;
  283.       end;
  284.     end;
  285.   end;
  286.  
  287.   LoadINI := 0;
  288.   close(T);
  289. end;
  290.  
  291. procedure FreeINI;
  292. begin
  293.   while List <> nil do
  294.   begin
  295.     StrDispose(List^.Entry);
  296.     StrDispose(List^.Value);
  297.     LNew := List;
  298.     List := List^.Next;
  299.     Dispose(Lnew);
  300.   end;
  301. end;
  302.  
  303. function GetEntry(Entry: TEntry; const Default: string): string;
  304. var
  305.   NotFound: Boolean;
  306. begin
  307.   NotFound := True;
  308.   LNew := List;
  309.   Entry := uppercase(Entry);
  310.   {Make this a PCHAR so we can use StrComp on it}
  311.   Temp := Pas2Pchar(Entry);
  312.   while (LNew <> nil) and NotFound do
  313.   begin
  314.     if StrComp(Lnew^.Entry, Temp) = 0 then
  315.     begin
  316.       NotFound := False;
  317.       GetEntry := PChar2Pas(LNew^.Value);
  318.     end;
  319.     Lnew := LNew^.Next;
  320.   end;
  321.   {Return Default uppercase, to provide consistancy}
  322.   if NotFound then GetEntry := uppercase(Default);
  323. end;
  324.  
  325. end.
  326.